Crate astra

source ·
Expand description

Astra

Crate Github Docs

A synchronous HTTP server built on top of hyper.

use astra::{Body, Response, Server};

fn main() {
    Server::bind("localhost:3000")
        .serve(|_req| Response::new(Body::new("Hello World!")))
        .expect("serve failed");
}

How Does It Work?

Hyper is built on async I/O and depends on it to run correctly, so Astra runs a small evented I/O loop under the hood. It dispatches incoming connections to a scalable worker pool, handing off async I/O sources to Hyper. The difference is that instead of yielding to a userspace runtime like Tokio, workers yield to the operating system scheduler. This means that services can use standard I/O primitives without worrying about blocking an event loop:

use astra::{Body, ResponseBuilder, Server};
use std::time::Duration;

fn main() {
    Server::bind("localhost:3000")
        .serve(|_req| {
            // Putting the worker thread to sleep will allow
            // other workers to run.
            std::thread::sleep(Duration::from_secs(1));

            // Regular blocking I/O is fine too!
            let body = std::fs::read_to_string("index.html").unwrap();

            ResponseBuilder::new()
                .header("Content-Type", "text/html")
                .body(Body::new(body))
                .unwrap()
        })
        .expect("serve failed");
}

Features

Astra supports both HTTP/1 and HTTP/2 with most the configuration options that Hyper exposes. Features that depend on Tokio however, such as http2_keep_alive_while_idle, are not supported and blocked on better hyper support.

Astra is currently an HTTP server library only. The client API is unimplemented.

But Is It Fast?

Many of the references you’ll find about thread-per-request performance are very outdated, often referencing bottlenecks from a time where C10k was peak scale. Since then, thread creation has gotten significantly cheaper, and context switching overhead has been reduced drastically. Modern OS schedulers are much better than they are given credit for, and it is now very feasible to serve upwards of tens of thousands of concurrent connections using synchronous I/O.

In naive “Hello World” style HTTP benchmarks, Astra is likely to lag behind Tokio. This is partly because Astra has to pay the cost of both threading and asynchronous I/O to be compatible with Hyper. However, as more work is done per request, especially pure blocking I/O, the difference diminishes. As always, you should measure your own use case, but Astra’s performance may surprise you.

That being said, one Astra’s main use cases is running a lightweight server with minimal dependencies, and avoiding the complexity that comes with async, so any potential performance tradeoff might not be be relevant.

Structs

The streaming body of an HTTP request or response.
An HTTP server.

Traits

A service capable of responding to an HTTP request.

Type Definitions

An HTTP request.
An HTTP response.
A builder for an HTTP response.